package cn.jy.generate;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.jy.common.annotation.ExportParameter;
import cn.jy.generate.pojo.*;
import cn.jy.generate.utils.ConvertUtil;
import cn.jy.generate.pojo.*;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

import static cn.jy.generate.constant.DbConstant.*;

/**
 * 生成代码
 * author: ljw
 */
@Log4j2
public class GenerateExportApplication extends GenerateCodeApplication {


	@SneakyThrows
	public static void main(String[] args) {

		// 1.获取配置表父子关系
		Map<String, ConfTable> sonParentMap = new HashMap<>(); // 配置-子表名对应父表
		Map<String, List<ConfTable>> parentSonMap = new HashMap<>(); // 配置-父表名对应子表
		Map<String, ConfTable> selfMap = new HashMap<>(); // 配置-自包含
		getTableRelation(sonParentMap, parentSonMap, selfMap);

		// 2.数据库连接：获取表结构
		getDBStructure(selfMap);

		// 3.生成对应文件
		sonGenerateCode(sonParentMap, parentSonMap, selfMap);


	}


	/**
	 * 生成代码
	 */
	private static void sonGenerateCode(Map<String, ConfTable> sonParentMap,
                                        Map<String, List<ConfTable>> parentSonMap, Map<String, ConfTable> selfMap) throws IOException, SQLException {

		Map<String, Map<String, Object>> tableCodeAndDataMap = new HashMap<>();
		Map<String, RenderingEnum> enumMap = new HashMap<>();
		Map<String, List<RenderingDict>> dictMap = new HashMap<>();

		// 获取所有共享参数
		generalData(sonParentMap, parentSonMap, selfMap, tableCodeAndDataMap, enumMap, dictMap);

		// 生成vo等业务代码
		generalBusiness(tableCodeAndDataMap);

		// 生成代码
		sonGeneralBusiness(tableCodeAndDataMap);


	}


	/**
	 * 生成业务代码.
	 *
	 * @param tableCodeAndDataMap
	 * @throws FileNotFoundException
	 */
	private static void sonGeneralBusiness(Map<String, Map<String, Object>> tableCodeAndDataMap) throws IOException, SQLException {

		// 生成字典代码或者枚举sql
		String dictDirStr = "template/common/";
		ClasspathResourceLoader dictResourceLoader = new ClasspathResourceLoader(dictDirStr);
		Configuration cfg = Configuration.defaultConfiguration();
		// 路径
		File dictDir = ResourceUtils.getFile("classpath:" + dictDirStr);
		List<File> dictTempList = getDirectoryFiles(dictDir, "export_column");
		GroupTemplate dictGt = new GroupTemplate(dictResourceLoader, cfg);

		String apiBackend = strategyConfig.getGenerateApiPath();

		// 加载驱动
		// 数据库连接
		Statement statement = null;
		Connection connection = null;
		try {
			Class.forName(dbConfig.getDbDriver());
			connection = DriverManager.getConnection(dbConfig.getDbUrl(), dbConfig.getDbUserName(), dbConfig.getDbUserPassword());
			statement = connection.createStatement();
		} catch (ClassNotFoundException | SQLException e) {
			throw new RuntimeException(e);
		}

		Statement finalStatement = statement;
		// 排除表
		List<String> excludeTableList = strategyConfig.getExcludeTable();
		tableCodeAndDataMap.forEach((key, shared) -> {
			if (excludeTableList == null || !excludeTableList.contains(key)) {
                for (File file : dictTempList) {
					List<RenderingDict> deleteDictList = new ArrayList<>();
					List<RenderingDict> addDictList = new ArrayList<>();
					List<RenderingDict> updateDictList = new ArrayList<>();

					String className = (String) shared.get("className");
					String module = (String) shared.get("module");
					String ddlTableComment = (String) shared.get("ddlTableComment");

					String classPackageName = strategyConfig.getPackagePath() + "." + module + ".vo." + className;
					String voClassPath = apiBackend + "target\\classes";
					File VOFile = new File(voClassPath);
					if (!VOFile.exists()) {
						throw new RuntimeException("文件无法找到：" + voClassPath);
					}
					// 创建自定义类加载器，指定类文件路径
					CustomClassLoader customClassLoader = new CustomClassLoader(voClassPath);

					try {
						// 使用自定义加载器加载类
						Class<?> clazz = customClassLoader.findClass(classPackageName + "VO");
						Class<?> superclass = clazz.getSuperclass();
						System.out.println("成功加载类: " + clazz.getName());

						// 获取该类对应的字段信息（即业务导出列）
						List<DownLoadProperty> businessOrgin = getBusinessOrgin(clazz);
						if (CollectionUtil.isEmpty(businessOrgin)) {
							return;
						}
						if (superclass != null) {
							List<DownLoadProperty> superBusinessOrgin = getBusinessOrgin(superclass);
							System.out.println("成功加载父类: " + superclass.getName());
							if (!CollectionUtil.isEmpty(superBusinessOrgin)) {
								businessOrgin.addAll(superBusinessOrgin);
							}
						}
						// 生成sql文件
						// 数据库
						String bizType = "EXPORT_" + shared.get("bizType");
						String dbDictTableName = dbConfig.getDbDictTableName();
						if (StrUtil.isBlank(dbDictTableName)){
							throw new RuntimeException("配置的字典表名为空：dbDictTableName");
						}
						List<RenderingDict> xhDictList = getDBDictStructure(finalStatement, dbDictTableName, bizType);

						RenderingDict parentDict = new RenderingDict();
						if (CollectionUtil.isNotEmpty(xhDictList)){
							List<RenderingDict> list = xhDictList.stream().filter(dict -> 0L == dict.getParentId()).toList();
							if (CollectionUtil.isNotEmpty(list)){
								parentDict = list.getFirst();
							}
						} else {
							//字典不存在先加父节点
							parentDict.setId(IdUtil.getSnowflakeNextId());
							parentDict.setCode(bizType);
							parentDict.setParentId(0L);
							parentDict.setDictKey("");
							parentDict.setSort(200);
							parentDict.setDictValue(ddlTableComment + "导出列");
							addDictList.add(parentDict);
						}

						// 存储 dictKey 的集合，用于检查是否需要删除 dict
						Set<String> dictKeySet = new HashSet<>();
						// 对比已有的dict数据，存在则查询更新，不存在则删除，新增
						for (DownLoadProperty property : businessOrgin) {
							String annotation = property.getAnnotation();
							String field = property.getField();
							//字典注释只取前面的 如：审核状态：0-未审核-NOT_AUDIT；1-审核中-AUDIT_ING；2-审核完成-AUDIT 只取 审核状态
							if (StrUtil.isNotBlank(annotation)) {
								if (annotation.contains("：")) {
									annotation = annotation.split("：")[0];
								}
							}
							boolean dictFound = false;  // 标记是否找到对应的 dict

							// 遍历现有的 xhDictList，检查是否存在对应的 dict
							for (RenderingDict dict : xhDictList) {
								//跳过父节点
								if (0L == dict.getParentId()) {
									continue;
								}
								if (field.equals(dict.getDictKey())) {  // 如果 dict 已存在
									dictFound = true;
									dict.setDictValue(annotation);  // 更新 dict 的值
									dict.setSort(businessOrgin.indexOf(property) + 1);  // 更新排序
									updateDictList.add(dict);  // 加入更新列表
									dictKeySet.add(dict.getDictKey());  // 记录 dict 已经处理过
									break;  // 找到对应的 dict 后退出循环
								}
							}

							// 如果 dict 不存在，新增 RenderingDict
							if (!dictFound) {
								RenderingDict renderingDict = new RenderingDict();
								renderingDict.setId(IdUtil.getSnowflakeNextId());
								renderingDict.setCode(parentDict.getCode());
								renderingDict.setDictKey(field);
								renderingDict.setDictValue(annotation);
								renderingDict.setSort(businessOrgin.indexOf(property) + 1);
								renderingDict.setParentId(parentDict.getId());  // 假设这里需要使用 parentDict 的 id
								addDictList.add(renderingDict);  // 加入新增列表
							}
						}

						// 删除存在但不在 businessOrgin 列表中的 dict
						for (RenderingDict dict : xhDictList) {
							//跳过父节点
							if (0L == dict.getParentId()) {
								continue;
							}
							if (!dictKeySet.contains(dict.getDictKey())) {
								deleteDictList.add(dict);  // 加入删除列表
							}
						}
						Template dictTemplate = dictGt.getTemplate(file.getName());
						String orgFileName = file.getName().replace(".flt", "");
						String fileName = ConvertUtil.removePrefixAndSuffix(orgFileName);
						String fileEnd = ConvertUtil.upperFirst(fileName) + "Dict";
						dictTemplate.binding("deleteDictList", deleteDictList);
						dictTemplate.binding("addDictList", addDictList);
						dictTemplate.binding("updateDictList", updateDictList);
//						System.out.println("需要删除的导出列：deleteDictList = " + deleteDictList);
//						System.out.println("需要新增的导出列：addDictList = " + addDictList);
//						System.out.println("需要更新的导出列：updateDictList = " + updateDictList);
						String createPath = strategyConfig.getGenerateScriptPath() + "/sql/EXPORT_" + className + fileEnd + "Sql.sql";
						createFile(dictTemplate, createPath);
//						System.out.println(clazz + "-" + businessOrgin.stream().map(c -> c.getField() + "-" + c.getAnnotation()).collect(Collectors.joining(",")));
					} catch (IllegalAccessException e) {
						log.error("导出列获取异常，具体原因：{}", e.getMessage());
					} catch (ClassNotFoundException | SQLException e) {
						throw new RuntimeException(e);
					}


				}
			}
		});

		statement.close();
		connection.close();
	}



	/**
	 * 获取数据库表真实结构.
	 */
	static List<RenderingDict> getDBDictStructure(Statement statement, String tableName, String bizType) throws SQLException, ClassNotFoundException {
		try {
			// 表信息
			String tableDictExecuteSql = String.format(getDictSql, dbConfig.getDbDictDatabase(), tableName, bizType);
			System.out.println("执行sql语句tableDictExecuteSql：" + tableDictExecuteSql);
			ResultSet resultSet = statement.executeQuery(tableDictExecuteSql);
			List<RenderingDict> dictInfoList = new ArrayList<>();
			while (resultSet.next()) {
				RenderingDict dictInfo = new RenderingDict();
				dictInfo.setId(resultSet.getLong("id"));
				dictInfo.setParentId(resultSet.getLong("parent_id"));
				dictInfo.setCode(resultSet.getString("code"));
				dictInfo.setDictKey(resultSet.getString("dict_key"));
				dictInfo.setDictValue(resultSet.getString("dict_value"));
				dictInfo.setSort(resultSet.getInt("sort"));
				dictInfo.setRemark(resultSet.getString("remark"));
				dictInfoList.add(dictInfo);
			}
			return dictInfoList;
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}


	protected static List<DownLoadProperty> getBusinessOrgin(Class clazz) throws IllegalAccessException {
		// 返回值
		List<DownLoadProperty> ret = new ArrayList<>();

		// 通过反射ErpMaterialProductionInfoVO 类的所有字段和注释
		Field[] declaredFields = clazz.getDeclaredFields();

		List<String> exclude = List.of("serialVersionUID", "version", "createUser", "updateUser");

		if (strategyConfig.getGenerateExportParameter() == null) {
			throw new RuntimeException("配置的导出类为空：ExportParameter");
		}
		for (Field field : declaredFields) {
			String f = field.getName();
			if (exclude.contains(f)) {
				continue;
			}
			// 通过反射获取字段上的注解
			Annotation annotation = null;
			String annotationDescription = null;
			if ("cn.jy.common.annotation.ExportParameter".equals(strategyConfig.getGenerateExportParameter())) {
				annotation = field.getAnnotation(cn.jy.common.annotation.ExportParameter.class);
				if (annotation == null) {
					continue;
				}
				annotationDescription = field.getAnnotation(cn.jy.common.annotation.ExportParameter.class).description();
			}

			DownLoadProperty property = new DownLoadProperty().setAnnotation(annotationDescription).setField(f);
			ret.add(property);
		}
		Class superclass = clazz.getSuperclass();
		if (superclass != null) {
			Field[] superclassDeclaredFields = superclass.getDeclaredFields();
			for (Field field : superclassDeclaredFields) {
				String superField = field.getName();
				if (exclude.contains(superField)) {
					continue;
				}

				if (field.getAnnotation(ExportParameter.class) == null) {
					continue;
				}
				String annotation = field.getAnnotation(ExportParameter.class).description();

				DownLoadProperty property = new DownLoadProperty().setAnnotation(annotation).setField(superField);
				ret.add(property);
			}
		}

		return ret;
	}


}

